package client.redis.impl;

import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;

import com.alibaba.fastjson.JSON;

import client.redis.RedisTreeNode;
import core.AlertUtil;
import core.FormDialog;
import javafx.scene.control.TextField;
import javafx.scene.control.TreeItem;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.ListPosition;
import redis.clients.jedis.Tuple;

/**
 * 单台redis连接客户端
 * @author self
 *
 */
public class SingleRedisClientImpl extends AbstractRedisClientImpl {

	//客户端名称
	private static final String CLIENT_NAME = "Redis客户端(单机)";
		
	//Jedis客户端
	private Jedis jedis;
	
	//连接信息
	private ConnectInfo connectInfo;
	
	@Override
	public String getName() {
		return CLIENT_NAME;
	}
	
	/**
	 * 创建连接
	 * @return
	 */
	protected boolean createConnection() {
		appLogger.info("创建Socket连接！");
		TextField hostTextField = new TextField("127.0.0.1");
		TextField portTextField = new TextField("6379");
		TextField authTextField = new TextField();
		FormDialog newConnForm = new FormDialog("新建链接"
					,new FormDialog.Item("主机：", hostTextField)
					,new FormDialog.Item("端口：", portTextField)
					,new FormDialog.Item("认证：", authTextField));
		Optional<Boolean> result = newConnForm.showAndWait();
		if(result.isPresent()) {
			String host = hostTextField.getText();
			int port = Integer.valueOf(portTextField.getText());
			String auth = authTextField.getText();
			appLogger.info("Socket连接参数 -> host:"+host+",port:"+port+",auth:"+auth);
			connectInfo = new ConnectInfo(host, port, auth);
			jedis = new Jedis(host, port);
			if(auth!=null&&!"".equals(auth.trim())) {
				jedis.auth(auth.trim());
			}
			this.controller.getCmdTextArea().setText("已连接！\n");
			appLogger.info("已连接到Redis服务器。");
			initTreeView();
		}
		return false;
	}
	
	/**
	 * 获取根节点
	 * @return　根节点对象
	 */
	protected TreeItem<RedisTreeNode> getRootTreeItem() {
		return this.getRootTreeItem(connectInfo.getHost()+":"+connectInfo.getPort());
	}
	
	@Override
	protected void select(int db) {
		if(jedis.getDB()!=db) {
			jedis.select(db);
		}
	}
	
	@Override
	protected void linsert(int db,String key,ListPosition where,String pivot,String value) {
		this.select(db);
		jedis.linsert(key, where, pivot, value);
	}
	
	@Override
	protected void rpush(int db, String key, String value) {
		this.select(db);
		jedis.rpush(key, value);
	}

	@Override
	protected void lpush(int db, String key, String value) {
		this.select(db);
		jedis.lpush(key, value);
	}
	
	@Override
	protected void lset(int db, String key, long index, String value) {
		this.select(db);
		jedis.lset(key, index, value);
	}
	
	@Override
	protected void lpop(int db, String key) {
		this.select(db);
		jedis.lpop(key);
	}
	
	@Override
	protected void rpop(int db, String key) {
		this.select(db);
		jedis.rpop(key);
	}
	
	@Override
	protected void srem(int db, String key, String item) {
		this.select(db);
		jedis.srem(key, item);
	}

	@Override
	protected void zrem(int db, String key, String item) {
		this.select(db);
		jedis.zrem(key, item);
	}

	@Override
	protected void lrem(int db, String key, String item) {
		this.select(db);
		jedis.lrem(key, 0, item);
	}

	@Override
	protected void hdel(int db, String key, String item) {
		this.select(db);
		jedis.hdel(key, item);
	}
	
	@Override
	protected void rename(int db,String key,String newName) {
		this.select(db);
		jedis.rename(key,newName);
	}
	
	@Override
	protected String type(int db, String key) {
		this.select(db);
		return jedis.type(key);
	}

	@Override
	protected Set<String> keys(int db, String string) {
		this.select(db);
		return jedis.keys(string);
	}
	
	@Override
	protected String getRedisInfo() {
		return jedis.info();
	}

	@Override
	protected String getDBInfo(int db) {
		this.select(db);
		long dbSize = jedis.dbSize();
		Map<String,Object> dbInfo = new HashMap<String, Object>();
		dbInfo.put("db", db);
		dbInfo.put("dbSize", dbSize);
		return JSON.toJSONString(dbInfo, true);
	}

	@Override
	protected Long ttl(int db, String key) {
		this.select(db);
		return jedis.ttl(key);
	}

	@Override
	protected String get(int db, String key) {
		this.select(db);
		return jedis.get(key);
	}

	@Override
	protected Set<String> smembers(int db, String key) {
		this.select(db);
		return jedis.smembers(key);
	}

	@Override
	protected Set<Tuple> zrangeWithScores(int db, String key, int i, int j) {
		this.select(db);
		return jedis.zrangeWithScores(key,i,j);
	}

	@Override
	protected List<String> lrange(int db, String key, int i, int j) {
		this.select(db);
		return jedis.lrange(key, i, j);
	}

	@Override
	protected Map<String, String> hgetAll(int db, String key) {
		this.select(db);
		return jedis.hgetAll(key);
	}
	
	@Override
	protected void set(int db, String name, String value) {
		this.select(db);
		jedis.set(name,value);
	}

	@Override
	protected void sadd(int db, String name, String[] array) {
		this.select(db);
		jedis.sadd(name, array);
	}

	@Override
	protected void sadd(int db, String name, String value) {
		this.select(db);
		jedis.sadd(name, value);
	}

	@Override
	protected void zadd(int db, String name, Map<String, Double> data) {
		this.select(db);
		jedis.zadd(name,data);
	}

	@Override
	protected void lpush(int db, String name, String[] array) {
		this.select(db);
		jedis.lpush(name,array);
	}

	@Override
	protected void hset(int db, String name, Map<String, String> data) {
		this.select(db);
		jedis.hset(name,data);
	}

	@Override
	protected void del(int db, String key) {
		this.select(db);
		jedis.del(key);
	}

	@Override
	protected void expire(int db, String key, int expire) {
		this.select(db);
		jedis.expire(key,expire);
	}

	@Override
	protected void persist(int db, String key) {
		this.select(db);
		jedis.persist(key);
	}
	
	@Override
	protected void flushDB(int db) {
		this.select(db);
		jedis.flushDB();
	}
	
	@Override
	public String exeCmd(String cmd) {
		if(cmd==null||"".equals(cmd.trim())) {
			return null;
		}
		try {
			appLogger.info("执行命令："+cmd);
			//命令如果没有换行符则补充一个
			if(!cmd.endsWith("\n")) {
				cmd+="\n";
			}
			
			/*
			 * 将命令写入Socket
			 */
			OutputStream output = jedis.getClient().getSocket().getOutputStream();
			output.write(cmd.getBytes(StandardCharsets.UTF_8));
			
			/*
			 * 从Socket读取响应
			 */
			StringBuilder builder = new StringBuilder(); 
			InputStreamReader input = new InputStreamReader(jedis.getClient().getSocket().getInputStream(),StandardCharsets.UTF_8);
			char[] chareBuf = new char[1024];
			int len;
			while((len=input.read(chareBuf))!=-1) {
				builder.append(chareBuf,0,len);
				if(len<chareBuf.length) {
					break;
				}
			}
			String result=builder.toString();
			appLogger.info("执行结果："+result);
			return result;
		} catch (IOException e) {
			AlertUtil.exception(e);
		}
		return null;
	}

	@Override
	public void close() throws IOException {
		if(jedis!=null) {
			jedis.close();
		}
	}
	
	private static class ConnectInfo{
		private String host;
		private int port;
		private String auth;
		
		public ConnectInfo(String host,int port,String auth) {
			this.host = host;
			this.port = port;
			this.auth = auth;
		}
		
		public String getHost() {
			return host;
		}
		
		public int getPort() {
			return port;
		}
		
		public String getAuth() {
			return auth;
		}
	}
}
